import imp
import os.path
import logging

EGG = True
try:
    import pkg_resources
except:
    EGG = False
    pass

from framework.myexceptions import MyException

class ModuleMan:
    """
    handles the load of python extensions.
    """

    def __init__(self, module_loader, base_path, dir_name, create_inst = True, api = None):
	self.__logger = logging.getLogger("framework.ModuleManager")

	self.create_inst = create_inst
	self.module_loader = module_loader
	self.base_path = base_path
	self.api = api
	self.dir_name = dir_name

	self.load_all(dir_name)

    # ------------------------- load scripts functions --------------------------------

    def load_egg_from_file(self, fullName):
	self.__logger.debug('load_egg_from_file. START, file=%s' % (fullName,))

	if not EGG:
	    self.__logger.critical('load_egg_from_file. No support to load .egg plugins. Install package pkg_resources.')
	    return

	dir, filename = os.path.split(fullName)
	fn = os.path.splitext(filename)[0]
	id = dir.split(self.dir_name)[1][1:] + '/' + fn
	if id.startswith('/'): id = id[1:]

	pkg_resources.working_set.add_entry(fullName)
	dist_generator = pkg_resources.find_distributions(fullName)
	for dist in dist_generator:
	    try:
		extension_class = dist.load_entry_point("pysqlin.plugins", "plugin")
		# create an instance of the class
		extension = extension_class(self.api)
		self.__register(extension, id)
	    except Exception, e :
		self.__logger.critical('load_egg_from_file. Exception, msg=%s' % (e,))
	    
    def load_py_from_file(self,filename):
	"""
	Opens "filename" and loads the python code into a module
	"""

	self.__logger.debug('load_py_from_file. START, file=%s' % (filename,))

	dir, filename = os.path.split(filename)

	fn = os.path.splitext(filename)[0]
	exten_file = None

	id = dir.split(self.dir_name)[1][1:] + '/' + fn
	if id.startswith('/'): id = id[1:]

	try:
	    exten_file, filename, description = imp.find_module(fn, [dir])
	    module = imp.load_module(fn, exten_file, filename, description)
	    self.__register(module, id)
	except ImportError, msg:
	    self.__logger.critical('load_py_from_file. Exception, msg=%s' % (msg,))
	except SyntaxError, msg:
	    # incorrect python syntax in file
	    self.__logger.critical('load_py_from_file. Exception, msg=%s' % (msg,))
	finally:
	    if exten_file: exten_file.close()

	self.__logger.debug('load_py_from_file. END, loaded file=%s' % (filename,))
	    
    def __register(self, script, id):
	"""
	Checks script module and saves it in memory 
	Returns false/true when failure/success
	"""

	# check if the necessary attributes are present
	requiredAttributes = ("load",)
	missingAttrs = []
	for attr in requiredAttributes:
	    if not hasattr(script, attr):
		missingAttrs.append(attr)

	if missingAttrs:
	    self.__logger.debug('__register. Exception: Module must define required attributes')
	    raise MyException('__register. Exception: Module must define required attributes')

	try:
	    if self.create_inst:
		self.module_loader.register(id, script.load(self.api))
	    else:
		self.module_loader.register(id, script)
	except MyException, msg:
	    self.__logger.critical('__register. Exception, msg=%s' % (msg,))

    def load_all(self, dir_name):
	"""
	loads all plugins and creates a loaded list of scripts from directory plugins like:
	[ ( category,[script1, script2,...] ), (category2,[script1, (subcategory,[script1,script2]),...]) ]
	"""
	scripts = []

	current = os.path.join(self.base_path, dir_name)
	if os.path.isdir(current):
	    l = self.__load_dir_tree(current)
	    scripts.append((current,l))
	    self.module_loader.end_loading(scripts)

    def __load_dir_tree(self, dir):
	l=[]

	self.__logger.debug('__load_dir_tree. START dir=%s', dir)

        for f in os.listdir(dir):
	    current = os.path.join(dir, f)
	    if os.path.isfile(current) and f.endswith("py"):
		self.load_py_from_file(current)
		l.append(os.path.splitext(f)[0])
	    elif os.path.isfile(current) and f.endswith("egg"):
		self.load_egg_from_file(current)
		l.append(os.path.splitext(f)[0])
	    elif os.path.isdir(current):
		ret = self.__load_dir_tree(current)
		if ret: l.append( (f,ret) )
	return l
